package com.autumn.zero.workflow.application.services.impl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;

import com.autumn.application.service.AbstractApplicationService;
import com.autumn.common.api.application.dto.input.AdvancedPageQueryInput;
import com.autumn.common.api.application.dto.input.AdvancedQueryInput;
import com.autumn.common.api.application.dto.input.IAdvancedPageQueryInput;
import com.autumn.common.api.application.dto.input.IAdvancedQueryInput;
import com.autumn.common.api.application.dto.input.IAdvancedSearchInput;
import com.autumn.common.api.application.dto.input.IQueryCriteriaInput;
import com.autumn.common.api.application.dto.output.IPageQueryResult;
import com.autumn.common.api.application.dto.output.PageQueryResult;
import com.autumn.mybatis.criterion.EntityQuery;
import com.autumn.mybatis.criterion.IQuerySection;
import com.autumn.mybatis.criterion.LogicalOperatorEnum;
import com.autumn.util.AutoMapUtils;
import com.autumn.util.ExceptionUtils;
import com.autumn.util.StringUtils;
import com.autumn.util.data.DbQueryUtils;
import com.autumn.util.excel.ExcelUtils;
import com.autumn.util.excel.WorkbookInfo;
import com.autumn.util.excel.export.GenericExportInfo;
import com.autumn.zero.workflow.application.dto.WorkflowImageInput;
import com.autumn.zero.workflow.application.dto.WorkflowImageOutput;
import com.autumn.zero.workflow.application.dto.user.task.UserTaskCompleteInput;
import com.autumn.zero.workflow.application.dto.user.task.WorkflowUserTaskCompleteOutput;
import com.autumn.zero.workflow.application.dto.user.task.WorkflowUserTaskDto;
import com.autumn.zero.workflow.application.services.IWorkflowUserTaskAppService;
import com.autumn.zero.workflow.entitys.AbstractWorkflowProcess;
import com.autumn.zero.workflow.entitys.AbstractWorkflowUserTask;
import com.autumn.zero.workflow.entitys.WorkflowUserTaskComplete;
import com.autumn.zero.workflow.entitys.WorkflowUserTaskWait;
import com.autumn.zero.workflow.entitys.querys.AbstractWorkflowUserTaskQuery;
import com.autumn.zero.workflow.entitys.querys.WorkflowUserTaskCompleteQuery;
import com.autumn.zero.workflow.entitys.querys.WorkflowUserTaskWaitQuery;
import com.autumn.zero.workflow.repositorys.querys.IWorkflowUserTaskCompleteQueryRepository;
import com.autumn.zero.workflow.repositorys.querys.IWorkflowUserTaskWaitQueryRepository;
import com.autumn.zero.workflow.services.IProcessService;
import com.autumn.zero.workflow.values.ProcessTaskCompleteValue;

/**
 * 
 * 工作流用户任务服务
 * 
 * @author 杨昌国 2019-02-20 18:14:26
 */
public class WorkflowUserTaskAppServiceImpl extends AbstractApplicationService implements IWorkflowUserTaskAppService {
	/**
	 * 
	 */
	public static final int EXCEL_EXPORT_MAX_ROW_COUNT = 65000;

	@Autowired
	private IProcessService processService;

	@Autowired
	private IWorkflowUserTaskWaitQueryRepository workflowUserTaskWaitQueryRepository;

	@Autowired
	private IWorkflowUserTaskCompleteQueryRepository workflowUserTaskCompleteQueryRepository;

	@Override
	public String getModuleName() {
		return "用户任务";
	}

	/**
	 * 获取Excel导出的最大行数
	 * 
	 * @return
	 */
	protected int getExcelExportMaxRowCount() {
		return EXCEL_EXPORT_MAX_ROW_COUNT;
	}

	/**
	 * 创建用户任务查询
	 * 
	 * @param criteriaInput 条件输入
	 * @param searchInput   搜索输入
	 * @param userTaskClass 用户任务类型
	 * @return
	 */
	private <TUserTask extends AbstractWorkflowUserTaskQuery> EntityQuery<TUserTask> createUserTaskQuery(
			IQueryCriteriaInput criteriaInput, IAdvancedSearchInput searchInput, Class<TUserTask> userTaskClass) {
		EntityQuery<TUserTask> query = new EntityQuery<>(userTaskClass);
		query.eq(AbstractWorkflowUserTask.FILED_USER_ID, this.getSession().getUserId().toString());
		query.criteria(DbQueryUtils.toCriteriaBeanList(criteriaInput.getCriterias()));
		if (!StringUtils.isNullOrBlank(searchInput.getSearchKeyword())) {
			query.like(LogicalOperatorEnum.AND, AbstractWorkflowUserTask.FILED_TASK_NAME,
					searchInput.getSearchKeyword());
			query.like(LogicalOperatorEnum.OR, AbstractWorkflowUserTask.FILED_TASK_NO, searchInput.getSearchKeyword());
		}
		query.orderByDescending(AbstractWorkflowUserTask.FILED_TASK_TIME)
				.orderByDescending(AbstractWorkflowUserTask.FILED_ID);
		return query;
	}

	@Override
	public IPageQueryResult<WorkflowUserTaskDto> queryTaskWaitByPageList(IAdvancedPageQueryInput input) {
		if (input == null) {
			input = new AdvancedPageQueryInput();
		}
		EntityQuery<WorkflowUserTaskWaitQuery> query = this.createUserTaskQuery(input, input,
				WorkflowUserTaskWaitQuery.class);
		IQuerySection querySection = query.builderSection();
		int count = workflowUserTaskWaitQueryRepository.countByWhere(querySection);
		PageQueryResult<WorkflowUserTaskDto> result = new PageQueryResult<>(input.getCurrentPage(), input.getPageSize(),
				count);
		query.page(result.getCurrentPage(), result.getPageSize());
		List<WorkflowUserTaskWaitQuery> entitys = workflowUserTaskWaitQueryRepository
				.selectList(query.builderSection());
		List<WorkflowUserTaskDto> items = AutoMapUtils.mapList(entitys, WorkflowUserTaskDto.class);
		result.setItems(items);
		return result;
	}

	@Override
	public Workbook exportTaskWaitByExcel(IAdvancedQueryInput input) {
		if (input == null) {
			input = new AdvancedQueryInput();
		}
		EntityQuery<WorkflowUserTaskWaitQuery> query = this.createUserTaskQuery(input, input,
				WorkflowUserTaskWaitQuery.class);
		IQuerySection querySection = query.builderSection();
		int count = workflowUserTaskWaitQueryRepository.countByWhere(querySection);
		int maxRowCount = this.getExcelExportMaxRowCount();
		if (count > maxRowCount) {
			ExceptionUtils.throwValidationException(String.format("需要导出的数据超过 %s 行，请通过条件限制。", maxRowCount));
		}
		List<WorkflowUserTaskWaitQuery> entitys = workflowUserTaskWaitQueryRepository.selectList(querySection);
		List<WorkflowUserTaskDto> items = AutoMapUtils.mapList(entitys, WorkflowUserTaskDto.class);
		GenericExportInfo<WorkflowUserTaskDto> exportInfo = new GenericExportInfo<>(WorkflowUserTaskDto.class);
		exportInfo.setItems(items);
		WorkbookInfo workbookInfo = ExcelUtils.getWorkbookInfo(WorkflowUserTaskDto.class, "待办任务");
		return workbookInfo.createExportWorkbook(exportInfo, false);
	}

	@Override
	public IPageQueryResult<WorkflowUserTaskCompleteOutput> queryTaskCompleteByPageList(IAdvancedPageQueryInput input) {
		EntityQuery<WorkflowUserTaskCompleteQuery> query = this.createUserTaskQuery(input, input,
				WorkflowUserTaskCompleteQuery.class);
		IQuerySection querySection = query.builderSection();
		int count = workflowUserTaskCompleteQueryRepository.countByWhere(querySection);
		PageQueryResult<WorkflowUserTaskCompleteOutput> result = new PageQueryResult<>(input.getCurrentPage(),
				input.getPageSize(), count);
		query.page(result.getCurrentPage(), result.getPageSize());
		List<WorkflowUserTaskCompleteQuery> entitys = workflowUserTaskCompleteQueryRepository
				.selectList(query.builderSection());
		List<WorkflowUserTaskCompleteOutput> items = AutoMapUtils.mapList(entitys,
				WorkflowUserTaskCompleteOutput.class);
		result.setItems(items);
		return result;
	}

	@Override
	public Workbook exportTaskCompleteByExcel(IAdvancedQueryInput input) {
		if (input == null) {
			input = new AdvancedQueryInput();
		}
		EntityQuery<WorkflowUserTaskCompleteQuery> query = this.createUserTaskQuery(input, input,
				WorkflowUserTaskCompleteQuery.class);
		IQuerySection querySection = query.builderSection();
		int count = workflowUserTaskCompleteQueryRepository.countByWhere(querySection);
		int maxRowCount = this.getExcelExportMaxRowCount();
		if (count > maxRowCount) {
			ExceptionUtils.throwValidationException(String.format("需要导出的数据超过 %s 行，请通过条件限制。", maxRowCount));
		}
		List<WorkflowUserTaskCompleteQuery> entitys = workflowUserTaskCompleteQueryRepository.selectList(querySection);
		List<WorkflowUserTaskCompleteOutput> items = AutoMapUtils.mapList(entitys,
				WorkflowUserTaskCompleteOutput.class);
		GenericExportInfo<WorkflowUserTaskCompleteOutput> exportInfo = new GenericExportInfo<>(
				WorkflowUserTaskCompleteOutput.class);
		exportInfo.setItems(items);
		WorkbookInfo workbookInfo = ExcelUtils.getWorkbookInfo(WorkflowUserTaskCompleteOutput.class, "已办任务");
		return workbookInfo.createExportWorkbook(exportInfo, false);
	}

	@Override
	public void userTaskComplete(UserTaskCompleteInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		ProcessTaskCompleteValue value = new ProcessTaskCompleteValue();
		value.setTaskId(input.getTaskId());
		value.setTaskOpinion(input.getTaskOpinion());
		value.setTaskResult(input.getTaskResult());
		value.setUserId(this.getSession().getUserId().toString());
		value.setUserName(this.getSession().getUserName());
		this.processService.taskComplete(value);
	}

	@Override
	public WorkflowImageOutput queryByWorkflowImage(WorkflowImageInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		AbstractWorkflowProcess workflowProcess;
		if (input.getFlowProcessId() != null) {
			workflowProcess = processService.queryWorkflowProcessById(input.getFlowProcessId());
		} else {
			workflowProcess = processService.queryWorkflowProcessByInstanceId(input.getProcessInstanceId());
		}
		if (workflowProcess == null) {
			return null;
		}
		WorkflowImageOutput workflowImage = AutoMapUtils.map(workflowProcess, WorkflowImageOutput.class);
		ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
		try {
			processService.writeFlowImageByInstanceId(workflowProcess.getProcessInstanceId(), swapStream);
			workflowImage.setImageBase64(new String(Base64.encodeBase64(swapStream.toByteArray())));
		} catch (IOException e) {
			this.getLogger().error(e.getMessage(), e);
		} finally {
			IOUtils.closeQuietly(swapStream);
		}
		return workflowImage;
	}

	/**
	 * 查询流程列表
	 * 
	 * @param input 输入
	 * @return
	 */
	@Override
	public List<WorkflowUserTaskCompleteOutput> queryByWorkflowList(WorkflowImageInput input) {
		ExceptionUtils.checkNotNull(input, "input");
		input.valid();
		AbstractWorkflowProcess workflowProcess;
		if (input.getFlowProcessId() != null) {
			workflowProcess = processService.queryWorkflowProcessById(input.getFlowProcessId());
		} else {
			workflowProcess = processService.queryWorkflowProcessByInstanceId(input.getProcessInstanceId());
		}
		List<WorkflowUserTaskCompleteOutput> items = new ArrayList<>();
		if (workflowProcess == null) {
			return items;
		}

		EntityQuery<WorkflowUserTaskCompleteQuery> taskCompleteQuery = new EntityQuery<>(
				WorkflowUserTaskCompleteQuery.class);
		taskCompleteQuery.eq(WorkflowUserTaskComplete.FILED_FLOW_ID, workflowProcess.getId())
				.orderBy(WorkflowUserTaskComplete.FILED_TASK_TIME);
		List<WorkflowUserTaskCompleteQuery> userTaskCompletes = taskCompleteQuery
				.selectByList(this.workflowUserTaskCompleteQueryRepository);
		items.addAll(AutoMapUtils.mapList(userTaskCompletes, WorkflowUserTaskCompleteOutput.class));

		EntityQuery<WorkflowUserTaskWaitQuery> taskWaitQuery = new EntityQuery<>(WorkflowUserTaskWaitQuery.class);
		taskWaitQuery.eq(WorkflowUserTaskWait.FILED_FLOW_ID, workflowProcess.getId())
				.orderBy(WorkflowUserTaskWait.FILED_TASK_TIME);
		List<WorkflowUserTaskWaitQuery> userTaskWaits = taskWaitQuery
				.selectByList(this.workflowUserTaskWaitQueryRepository);
		items.addAll(AutoMapUtils.mapList(userTaskWaits, WorkflowUserTaskCompleteOutput.class));

		/*
		 * items.sort(s -> {
		 * 
		 * 
		 * });
		 */

		return items;
	}

}
